﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SharpPcap;
using System;
using System.Diagnostics;
using System.Security.Policy;
using PacketDotNet;
using SharpPcap.LibPcap;
using static SharpPcap.LibPcap.Sockaddr;
using System.Collections.ObjectModel;
using System.Net.NetworkInformation;
using System.Net;
using System.Management;
using PacketDotNet.Tcp;
using System.Collections.Generic;
using System.Text;
using Net.http;

namespace HBase
{
    public class PacketServer {

        public uint  nextSqe=0;


        public PacketServer() {
        
            LibPcapLiveDevice device = getDevice("192.168.1.33");
            if (device == null) {
                Console.WriteLine("pcap ip error");

                return;
            }
            device.Open();
            device.OnPacketArrival += new PacketArrivalEventHandler(device_OnPacketArrival);
            device.StartCapture();

        }
        private void device_OnPacketArrival(object sender, RawCapture e) {
         
            byte[] data = e.Data;
            LibPcapLiveDevice device = (LibPcapLiveDevice)sender;

            Packet p = Packet.ParsePacket(e.LinkLayerType, data);
            if (!(p is EthernetPacket)) {
                return;
            }

            EthernetPacket ep = (EthernetPacket)p;
            if (ep.Type == EthernetPacketType.IpV4) {
                IPv4Packet packet = ep.PayloadPacket as IPv4Packet;
                PhysicalAddress from = ep.SourceHwAddress;
                PhysicalAddress to = ep.DestinationHwAddress;
                var ethernetPacket = new EthernetPacket(to, from,  EthernetPacketType.IpV4);
               
                doTcp(ethernetPacket, device, ep, packet);
            }
        }
        LibPcapLiveDevice getDevice(String ip) {
            List<LibPcapLiveDevice> devices = Pcap.Devices( "");
            if (devices.Count < 1) {
                Console.WriteLine("No devices were found on this machine");
                BaseConfig.Working = true;
                return null;
            }
            foreach (var dev in devices) {
                LibPcapLiveDevice d = (LibPcapLiveDevice)dev;
                ReadOnlyCollection<PcapAddress> adds = d.Addresses;

                foreach (PcapAddress pcapAddress in adds) {
                    if (pcapAddress.Addr.type == Sockaddr.AddressTypes.AF_INET_AF_INET6 && pcapAddress.Addr.sa_family == 2) {//pcapAddress.Addr.sa_family == Pcap.AF_INET
                        IPAddress addr = pcapAddress.Addr.ipAddress;
                        if (addr.ToString() == ip) {
                            NetConfig.MeIp = addr.ToString();
                            return d;
                        }

                    }
                }
            }

            return null;
        }

        void doTcp(EthernetPacket newP, LibPcapLiveDevice device, EthernetPacket back, IPv4Packet packet) {
            if (packet.Protocol != IPProtocolType.TCP) { 
                return;
            }
            TcpPacket oldTcp = packet.PayloadPacket as TcpPacket;
            if (oldTcp.DestinationPort != 12137) {
                return;
            }
             
            uint next = oldTcp.SequenceNumber + packet.PayloadLength - 20;

            nextSqe = nextSqe > next ? nextSqe : next;
            IPv4Packet res = new IPv4Packet(packet.DestinationAddress, packet.SourceAddress);
            newP.PayloadPacket = res;
            if (oldTcp.AllFlags == 16) {
                byte[] b = oldTcp.PayloadData;
                if (b.Length == 1 && b[0] == 0) {//keep alive
                    //reset(device, newP, res, oldTcp);
                    fin(device, newP, res, oldTcp);
                }
                return;
            } 
          
            if (oldTcp.Syn) {
                if (!oldTcp.Ack) {//首次请求
                    ask(device, newP, res, oldTcp);
                } else {
                    Console.WriteLine("tcp Ask error");
                }
            } else if (oldTcp.Ack) {
                doAsk(newP, res,device, back, packet, oldTcp);
            } else if (oldTcp.Rst) {
                //ask(device, newP, res, oldTcp);
                Console.WriteLine(packet.SourceAddress+"reset ");
            } else {
                Console.WriteLine("tcp  not syn not ask ");
            }
        }

        void doAsk(EthernetPacket newP, IPv4Packet res, LibPcapLiveDevice device, EthernetPacket back, IPv4Packet packet, TcpPacket oldTcp) {
            if (oldTcp.Fin) {//结束
                ask(device, newP, res, oldTcp);
                fin(device, newP, res, oldTcp);
            } else if (oldTcp.Psh) {//发送数据 
                byte[] p = oldTcp.PayloadData;
                string para = Encoding.UTF8.GetString(p);
                if (para.StartsWith("GET")) {
                    answer(device, newP, res, packet, oldTcp);
                    http(device, newP, res, packet, oldTcp);
                    //reset(device, newP, res, oldTcp);
                }

            } else { //客户端应答收到
              
            }

            Console.WriteLine(oldTcp.Fin+ "doAsk" + oldTcp.Psh);
        }
        void ask(LibPcapLiveDevice device, EthernetPacket newP, IPv4Packet res, TcpPacket oldTcp) {
            var tcp = new TcpPacket(oldTcp.DestinationPort, oldTcp.SourcePort);
      
            tcp.AcknowledgmentNumber = oldTcp.SequenceNumber + 1;
        
            tcp.Ack = true;
            tcp.Syn=oldTcp.Syn; 
            tcp.WindowSize= 1000;
            List<Option> option = oldTcp.OptionsCollection;
            tcp.SequenceNumber = TaskUtil.getQuee(tcp);
            res.PayloadPacket = tcp;
            res.UpdateCalculatedValues();
            res.UpdateIPChecksum();
            newP.UpdateCalculatedValues();
            tcp.UpdateTCPChecksum();


            byte[] b = newP.Bytes;
            String result = Convert.ToHexString(b);
            device.SendPacket(b);
        }

        void fin(LibPcapLiveDevice device, EthernetPacket newP, IPv4Packet res, TcpPacket oldTcp) {
            var tcp = new TcpPacket(oldTcp.DestinationPort, oldTcp.SourcePort);

            tcp.AcknowledgmentNumber = oldTcp.SequenceNumber + 1;
         
            tcp.Fin = true;
            tcp.Ack = true;
            tcp.WindowSize = 1000;
            tcp.SequenceNumber = TaskUtil.getQuee(tcp);
            List<Option> option = oldTcp.OptionsCollection;

            res.PayloadPacket = tcp;
            res.UpdateCalculatedValues();
            res.UpdateIPChecksum();
            newP.UpdateCalculatedValues();
            tcp.UpdateTCPChecksum();


            byte[] b = newP.Bytes;
            String result = Convert.ToHexString(b);
            device.SendPacket(b);
        }
        void reset(LibPcapLiveDevice device, EthernetPacket newP, IPv4Packet res, TcpPacket oldTcp) {
            var tcp = new TcpPacket(oldTcp.DestinationPort, oldTcp.SourcePort);

            tcp.AcknowledgmentNumber = oldTcp.SequenceNumber + 1;
          
            tcp.Rst = true; 
            tcp.WindowSize = 1000;
            List<Option> option = oldTcp.OptionsCollection;
            tcp.SequenceNumber = TaskUtil.getQuee(tcp);
            res.PayloadPacket = tcp;
            res.UpdateCalculatedValues();
            res.UpdateIPChecksum();
            newP.UpdateCalculatedValues();
            tcp.UpdateTCPChecksum();


            byte[] b = newP.Bytes;
            String result = Convert.ToHexString(b);
            device.SendPacket(b);
        }

        void answer(LibPcapLiveDevice device, EthernetPacket newP, IPv4Packet res, IPv4Packet packet, TcpPacket oldTcp) {
            var tcp = new TcpPacket(oldTcp.DestinationPort, oldTcp.SourcePort);
             
            tcp.AcknowledgmentNumber = oldTcp.SequenceNumber+(uint)oldTcp.PayloadData.Length;
       
            tcp.Ack = true;
            tcp.WindowSize = 1000;
            tcp.PayloadData = Encoding.Default.GetBytes("HTTP/1.0 200 OK");
            tcp.SequenceNumber = TaskUtil.getQuee(tcp);

            res.PayloadPacket = tcp;
            res.UpdateCalculatedValues();
            res.UpdateIPChecksum();
            newP.UpdateCalculatedValues();
            tcp.UpdateTCPChecksum();

            byte[] b = newP.Bytes;
            String result = Convert.ToHexString(b);
            device.SendPacket(b);
        }

        void http(LibPcapLiveDevice device, EthernetPacket newP, IPv4Packet res, IPv4Packet packet, TcpPacket oldTcp) {

            var tcp = new TcpPacket(oldTcp.DestinationPort, oldTcp.SourcePort);
 
            tcp.AcknowledgmentNumber = oldTcp.SequenceNumber + (uint)oldTcp.PayloadData.Length; ;
       
            tcp.Ack = true;
            tcp.Psh = true;
            tcp.Fin= true;
      
            tcp.WindowSize = 1000;
            tcp.PayloadData = UtilPackets.WriteSuccess("{sgj:"+DateTime.Now.Ticks+"}");
            tcp.SequenceNumber = TaskUtil.getQuee(tcp);
            res.PayloadPacket = tcp;
            res.UpdateCalculatedValues();
            res.UpdateIPChecksum();
            newP.UpdateCalculatedValues();
            tcp.UpdateTCPChecksum();
            tcp.UpdateCalculatedValues();
           
            byte[] b = newP.Bytes;
            String result = Convert.ToHexString(b);
            device.SendPacket(b);
        }
    } 
}
